package com.umpay.factory;

import java.io.ByteArrayInputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import com.umpay.util.ProFileUtil;

/**
 * 证书加载工厂
 * 
 * @ClassName RSACertFactory
 * @Description TODO
 * @author FENG JUN LIU
 * @Date 2018年1月29日
 * @version 1.0.0
 */
public class RSACertFactory {

    /**
     * 平台公钥
     */
    private static X509Certificate umfCert;

    private static Key umfPublicKey;
    /**
     * 商户私钥
     */
    private static final Map<String, PrivateKey> pkMap = new HashMap<String, PrivateKey>();
    /**
     * 商户私钥路径前缀
     */
    private static final String pkSuffix = ".mer.prikey.path";
    /**
     * 联动公钥路径
     */
    private static final String platCertPath = "plat.cert.path";
    /**
     * SignVerProp.properties 商户：plat.cert.path
     */
    static {
        try {
            byte[] b = ProFileUtil.getFileByte(platCertPath);
            umfCert = getCert(b);
            umfPublicKey = getPublicKey(umfCert);
        } catch (Exception ex) {
            RuntimeException rex = new RuntimeException(ex.getMessage());
            rex.setStackTrace(ex.getStackTrace());
            throw rex;
        }
    }

    public static Key getUmfPublicKey() {
        return umfPublicKey;
    }

    private static Key getPublicKey(X509Certificate x509Certificate) throws Exception {
        byte[] keyBytes = x509Certificate.getPublicKey().getEncoded();
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(x509KeySpec);
    }

    public static byte[] getCertByte() {
        byte[] b = null;
        try {
            b = ProFileUtil.getFileByte(platCertPath);
        } catch (Exception ex) {
            RuntimeException rex = new RuntimeException(ex.getMessage());
            rex.setStackTrace(ex.getStackTrace());
            throw rex;
        }
        return b;
    }

    public static PrivateKey getPk(String merId) {
        if (pkMap.containsKey(merId)) {
            return (PrivateKey) pkMap.get(merId);
        }
        synchronized (pkMap) {
            if (pkMap.containsKey(merId)) {
                return (PrivateKey) pkMap.get(merId);
            }
            try {
                byte[] b = ProFileUtil.getFileByte(merId + pkSuffix);
                PrivateKey retVal = getPk(b);
                pkMap.put(merId, retVal);
                return retVal;
            } catch (Exception ex) {
                RuntimeException rex = new RuntimeException(ex.getMessage());
                rex.setStackTrace(ex.getStackTrace());
                throw rex;
            }
        }
    }

    public static X509Certificate getUmfCert() {
        return umfCert;
    }

    private static X509Certificate getCert(byte[] b) {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(b);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            return (X509Certificate) cf.generateCertificate(bais);
        } catch (CertificateException e) {
            RuntimeException rex = new RuntimeException();
            rex.setStackTrace(e.getStackTrace());
            throw rex;
        }
    }

    private static PrivateKey getPk(byte[] key) {
        PrivateKey pk = null;
        try {
            PKCS8EncodedKeySpec e = new PKCS8EncodedKeySpec(key);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            pk = kf.generatePrivate(e);
        } catch (NoSuchAlgorithmException e) {
            RuntimeException rex = new RuntimeException();
            rex.setStackTrace(e.getStackTrace());
            throw rex;
        } catch (InvalidKeySpecException e) {
            RuntimeException rex = new RuntimeException();
            rex.setStackTrace(e.getStackTrace());
            throw rex;
        }
        return pk;
    }
}
